from django.views.generic import View
from django_celery_beat.models import (
    IntervalSchedule, CrontabSchedule, PeriodicTask,
    DAYS, HOURS, MINUTES, SECONDS, MICROSECONDS,
)
from django_celery_results.models import TaskResult
from celery import current_app
from celery.result import AsyncResult
from celery.states import PENDING, STARTED, RETRY, FAILURE, SUCCESS
from .forms import SchedulerForm, TaskForm, AsyncTaskForm
from utils.messages import Form_Invalid, Json_Response
from utils.decorators import permission_verify
from utils.paginate import paginate
from utils.fmt import datetime_str
from utils.record import record

# Create your views here.
IntervalType = {
    DAYS: '天',
    HOURS: '小时',
    MINUTES: '分钟',
    SECONDS: '秒',
    MICROSECONDS: '毫秒',
}
SchedulerType = ('interval', 'crontab', 'solar', 'clocked')


class SchedulerView(View):

    @permission_verify(30002)
    def interval_insert(self, request):
        # 间隔时间表
        form = SchedulerForm.IntervalInsert(request)
        if form.is_valid():
            data = form.cleaned_data
            if not IntervalSchedule.objects.filter(**data):
                IntervalSchedule.objects.create(**data)
                return Json_Response(msg='创建成功')
            else:
                return Json_Response(code=201, err_msg='时间表已经存在')
        else:
            return Form_Invalid(form)

    @permission_verify(30001)
    def interval_list(self, request):
        result = []
        for obj in IntervalSchedule.objects.all():
            result.append({
                'id': obj.id,
                'every': obj.every,
                'period': IntervalType[obj.period]
            })
        return Json_Response(msg='查询成功', data=result)

    @permission_verify(30002)
    def crontab_insert(self, request):
        # 定时时间表
        form = SchedulerForm.CrontabInsert(request)
        if form.is_valid():
            data = form.cleaned_data
            if not CrontabSchedule.objects.filter(**data):
                CrontabSchedule.objects.create(**data)
                return Json_Response(msg='创建成功')
            else:
                return Json_Response(code=201, err_msg='crontab时间表已经存在')
        else:
            return Form_Invalid(form)

    @permission_verify(30001)
    def crontab_list(self, request):
        result = []
        for obj in CrontabSchedule.objects.all().values_list(
                'id', 'minute', 'hour', 'day_of_week', 'day_of_month',
                'month_of_year', 'timezone', named=True):
            result.append({
                'id': obj.id,
                'minute': obj.minute,
                'hour': obj.hour,
                'day_of_week': obj.day_of_week,
                'day_of_month': obj.day_of_month,
                'month_of_year': obj.month_of_year,
                'timezone': str(obj.timezone),
            })
        return Json_Response(msg='查询成功', data=result)


class TaskView(View):

    def _get_scheduler_detail(self, type, id):
        '''
        :param type :one of scheduler_type
        '''
        result = None
        if type == 'interval':
            for obj in IntervalSchedule.objects.filter(id=id):
                result = '每 {} {}'.format(obj.every, IntervalType[obj.period])
        if type == 'crontab':
            for obj in CrontabSchedule.objects.filter(id=id):
                result = '{} {} {} {} {}'.format(
                    obj.minute, obj.hour, obj.day_of_week, obj.day_of_month, obj.month_of_year
                )

        return result

    def _get_system_tasks(self):
        tasks = list(
            sorted(
                name for name in current_app.tasks
                if name.startswith('celery.'))
        )
        return tasks

    def _get_customize_tasks(self):
        from celery_app import tasks
        # 需要导入任务模块，否则无法渠道已注册的任务
        tasks = list(
            sorted(
                name for name in current_app.tasks
                if not name.startswith('celery.'))
        )
        return tasks

    @permission_verify(30003)
    def get_tasks(self, request):
        tasks = []
        if '*' in request.USER_INFO['permissions']:
            tasks.extend(self._get_system_tasks())
        tasks.extend(self._get_customize_tasks())
        result = [
            {'id': i, 'value': i}
            for i in tasks
        ]
        return Json_Response(msg='查询成功', data=result)

    @permission_verify(30004)
    def change_status(self, request):
        form = TaskForm.ChangeStatus(request)
        if form.is_valid():
            data = form.cleaned_data
            id = data.pop('id')
            for obj in PeriodicTask.objects.filter(id=id):
                obj.enabled = data['enabled']
                obj.save()
            return Json_Response(msg='修改成功')
        else:
            return Form_Invalid(form)

    @permission_verify(30004)
    def insert(self, request):
        form = TaskForm.Insert(request)
        if form.is_valid():
            data = form.cleaned_data
            if not PeriodicTask.objects.filter(name=data['name']):
                PeriodicTask.objects.create(**data)
                return Json_Response(msg='创建成功')
            else:
                return Json_Response(code=201, err_msg='任务名重复')
        else:
            return Form_Invalid(form)

    @permission_verify(30004)
    def delete(self, request):
        form = TaskForm.Delete(request)
        if form.is_valid():
            PeriodicTask.objects.filter(id=form.cleaned_data['id']).delete()
            return Json_Response(msg='删除成功')
        else:
            return Form_Invalid(form)

    @permission_verify(30004)
    def update(self, request):
        form = TaskForm.Update(request)
        if form.is_valid():
            data = form.cleaned_data
            id = data.pop('id')
            task_qs = PeriodicTask.objects.filter(id=id)
            print(data)
            task_qs.update(**data)
            for obj in task_qs:
                obj.save()
            return Json_Response(msg='修改成功')
        else:
            return Form_Invalid(form)

    @permission_verify(30003)
    def list(self, request):
        form = TaskForm.List(request)
        if form.is_valid():
            result = []
            data = form.cleaned_data
            page, page_size = data.pop('page'), data.pop('page_size')

            qs = PeriodicTask.objects.filter()
            total = qs.count()

            for obj in paginate(qs, page, page_size).values_list(
                    'id', 'name', 'task',
                    'interval', 'crontab', 'solar', 'clocked',
                    'kwargs', 'args',
                    'expires', 'one_off', 'enabled', 'description',
                    'start_time', 'last_run_at', 'total_run_count', 'date_changed',
                    named=True
            ):
                s_type = None
                s_id = None
                s_value = None
                for t in SchedulerType:
                    s_id = getattr(obj, t)  # 时间表 实例
                    if s_id:
                        s_type = t
                        s_value = self._get_scheduler_detail(s_type, s_id)
                        break

                result.append({
                    'id': obj.id,
                    'name': obj.name,
                    'task': obj.task,
                    'description': obj.description,
                    'scheduler': {
                        'id': s_id,
                        'type': s_type,
                        'value': s_value,
                    },  # 时间表
                    'kwargs': obj.kwargs,
                    'args': obj.args,
                    'expires': datetime_str(obj.expires),
                    'one_off': obj.one_off,
                    'enabled': obj.enabled,
                    'start_time': datetime_str(obj.start_time),
                    'last_run_at': datetime_str(obj.last_run_at),
                    'total_run_count': obj.total_run_count,
                })
            return Json_Response(msg='查询成功', data={
                'page': page,
                'page_size': page_size,
                'total': total,
                'result': result
            })
        else:
            return Form_Invalid(form)


class AsyncTaskView(View):

    def get_result(self, request):
        form = AsyncTaskForm.Result(request.GET)
        if form.is_valid():
            result = {}
            task_id = form.cleaned_data['task_id']
            task = AsyncResult(task_id)
            status = task.state
            task_info = {
                'task_id': task_id,
                'task_name': task.name,
                'task_kwargs': task.kwargs,
                'status': status,
            }
            task_data = {

            }
            if status == SUCCESS or FAILURE:
                task_data = {
                    'result': str(task.result),
                    'tracback': task.traceback,
                    'date_done': task.date_done
                }

            result.update(task_info)
            result.setdefault('result', task_data)

            print(result)

            return Json_Response(msg='查询成功', data=result)
        else:
            return Form_Invalid(form)

    @permission_verify(30005)
    def result_list(self, request):
        form = AsyncTaskForm.ResultList(request)
        if form.is_valid():
            result = []
            data = form.cleaned_data
            page, page_size = data.pop('page'), data.pop('page_size')
            qs = TaskResult.objects.filter()
            total = qs.count()
            for obj in paginate(qs, page, page_size).values():
                obj['date_created'] = datetime_str(obj['date_created'])
                obj['date_done'] = datetime_str(obj['date_done'])
                result.append(obj)
            return Json_Response(msg='查询成功', data={
                'page': page,
                'page_size': page_size,
                'total': total,
                'result': result
            })
        else:
            return Form_Invalid(form)
